//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// Target Devices:
// Tool versions:
//
// Create Date:    2011-08-18 15:28
// Project Name:
// Description:
//      1.Read GUI data
//      2.Read CMOS data
//      3.Just support 240x320, because MCB read port max burst length is 64x32(256 byte).
//        Support 320x240 will be more complex in ddr read.
// Dependencies:
//
// Revision: 1.0
// Revision 0.01 - File Created
//
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns/1ns
module lcd_ctrl
#(
    parameter PCLK   = 2_870_000,  // 2.87MHz
    parameter SYS_CLK= 200_000_000,  // 200MHz
    parameter H_SIZE = 240,
    parameter V_SIZE = 320
)
(
    input               clk,
    input               rst,

    // config & status
    input [1:0]         x_buff_done,
    input [1:0]         y_buff_done,
    input [15:0]        disp_mode,
    input [15:0]        gui_id,
    output reg[15:0]    status,

    //ddr buffer read
    output              ddr_cmd_clk,
    output reg          ddr_cmd_en,
    output [2:0]        ddr_cmd_instr,
    output reg [5:0]    ddr_cmd_bl,
    output [29:0]       ddr_cmd_byte_addr,
    input               ddr_cmd_full,
    output              ddr_rd_clk,
    output reg          ddr_rd_en,
    input               ddr_rd_empty,
    input [31:0]        ddr_rd_data,

     //LCD port
    output reg [7:0]    lcd_r,
    output reg [7:0]    lcd_g,
    output reg [7:0]    lcd_b,
    output reg          lcd_pclk,
    output reg          lcd_de,
    output reg          lcd_hsync,
    output reg          lcd_vsync
);

/********************************************************\
Parameter
\********************************************************/
localparam  U_DLY           = 1;
localparam  DDR_RD          = 3'b001;
localparam  PCLK_PERX2      = SYS_CLK / (2*PCLK);

localparam  BUFF0_XBASE      = 30'h0;
localparam  BUFF0_XLAST      = 30'h9510;
localparam  BUFF0_YBASE      = 30'h9600;
localparam  BUFF0_YLAST      = 30'h1_2B10;

localparam  BUFF1_XBASE      = 30'h1_2C00;
localparam  BUFF1_XLAST      = 30'h1_C110;
localparam  BUFF1_YBASE      = 30'h1_C200;
localparam  BUFF1_YLAST      = 30'h2_5710;

localparam  GUI0_BASE       = 30'h2_5800;
localparam  GUI0_LAST       = 30'h5_D930;
localparam  GUI1_BASE       = 30'h5_DC00;
localparam  GUI1_LAST       = 30'h9_5D30;

localparam  CMOS_LEN        = V_SIZE * H_SIZE/4;
localparam  GUI_LEN         = V_SIZE * H_SIZE * 3/4;
localparam  CMOS_LINE_LEN   = H_SIZE;
localparam  GUI_LINE_LEN    = H_SIZE*3;
localparam  GUI_BL          = H_SIZE/4*3;
localparam  CMOS_BL         = H_SIZE/4;

// Hsync parameter Unit PCLK
localparam  Thp         = 30,
            Thb         = 38,
            Thb1        = Thp + Thb,
            Thd         = H_SIZE,
            Thd1        = Thb1 + Thd,
            Thf         = 20,
            Th          = Thp + Thb + Thd + Thf;

// Vsync parameter,Unit Th
localparam  Tvp         = 3,
            Tvb         = 15,
            Tvb1        = Tvp + Tvb,
            Tvd         = V_SIZE,
            Tvd1        = Tvb1 + Tvd,
            Tvf         = 12,
            Tv          = Tvp + Tvb + Tvd + Tvf;

/********************************************************\
Signals
\********************************************************/
wire                buff0_done;
wire                buff1_done;
reg                 ddr_buff_sel;
wire                buff_rdy;
// 2'b00 = gui; 2'b01 = gui+cmos_x;2'b10 = gui+cmos_y;2'b11 = gui+coms_x+cmos_y;disp_mode_reg[2] 0=normal, 1= invert
reg [15:0]          disp_mode_reg;
reg                 gui_sel_reg;
reg                 line_change;
reg                 line_rep;

reg [7:0]           pclk_cnt;
reg [15:0]          h_cnt;
reg [15:0]          v_cnt;
reg                 lcd_pclk_dly1;
wire                lcd_pclk_rising;
wire                lcd_pclk_falling;

reg                 lcd_hsync_dly1;
wire                lcd_hsync_rising;
wire                lcd_hsync_falling;
reg                 lcd_vsync_dly1;
wire                lcd_vsync_rising;
reg                 lcd_vsync_rising_dly;
reg                 h_enable;

reg                 ddr_rddata_sel; // 0 read data to gui_fifo, 1 read data to cmos_fifo;
reg                 ddr_cmd_sel;    // 0 gui fifo read command ,1 cmos fifo read command;
wire                ddr_rd_done;
reg [7:0]           ddr_rd_cnt;

reg [29:0]          gui_line_addr;
reg [31:0]          gui_pending_cnt;
wire [5:0]          gui_rd_bl;
wire                gui_done;
wire                gui_cmd_done;
wire                gui_line_done;
reg [7:0]           gui_line_bl;
reg [15:0]          gui_line_cnt;

reg [29:0]          cmos_line_addr;
reg [31:0]          cmos_pending_cnt;
wire [5:0]          cmos_rd_bl;
wire                cmos_done;
wire                cmos_cmd_done;
wire                cmos_line_done;
reg [7:0]           cmos_line_bl;
reg [15:0]          cmos_line_cnt;

reg [29:0]          line_point;

reg                 frame_done;

wire                gui_fifo_wr;
wire                gui_fifo_alfull;
wire                gui_fifo_rd;
wire [31:0]         gui_fifo_rddata;
wire                gui_fifo_alempty;
wire                gui_fifo_empty;

wire                cmos_fifo_wr;
wire                cmos_fifo_alfull;
wire                cmos_fifo_rd;
wire [31:0]         cmos_fifo_rddata;
wire                cmos_fifo_alempty;
wire                cmos_fifo_empty;

wire                wr_fifo_alfull;

reg                 buff_rdreq;
wire                gui_valid;
wire [7:0]          cmos_data;
wire [7:0]          gui_r;
wire [7:0]          gui_g;
wire [7:0]          gui_b;

/********************************************************\
main code
\********************************************************/
assign buff0_done = x_buff_done[0] & y_buff_done[0];
assign buff1_done = x_buff_done[1] & y_buff_done[1];
assign buff_rdy = buff0_done | buff1_done;
assign lcd_pclk_rising = ~lcd_pclk_dly1 & lcd_pclk;
assign lcd_pclk_falling = lcd_pclk_dly1 & (~lcd_pclk);
assign lcd_hsync_rising = ~lcd_hsync_dly1 & lcd_hsync;
assign lcd_hsync_falling = lcd_hsync_dly1 & (~lcd_hsync);
assign lcd_vsync_rising = ~lcd_vsync_dly1 & lcd_vsync;

assign ddr_cmd_clk = clk;
assign ddr_cmd_instr = DDR_RD;
assign ddr_cmd_byte_addr = line_point + ((ddr_cmd_sel==1'b0)?gui_line_addr:cmos_line_addr);
assign ddr_rd_clk = clk;
assign ddr_rd_done = (ddr_rd_cnt==0);
// ddr_cmd_bl value 0~63 means 1~64;
assign gui_rd_bl = (gui_line_bl > 8'd63)?8'd63:(gui_line_bl[5:0] - 1);
assign gui_done = (gui_pending_cnt==32'h0);
assign gui_line_done = gui_line_cnt==GUI_BL;
assign gui_cmd_done = (gui_line_bl < 8'd64) & ddr_cmd_en & (~ddr_cmd_sel);
assign cmos_rd_bl = (cmos_line_bl > 8'd63)?8'd63:(cmos_line_bl[5:0] - 1);
assign cmos_done = (cmos_pending_cnt==32'h0);
assign cmos_line_done = cmos_line_cnt==CMOS_BL;
assign cmos_cmd_done = (cmos_line_bl < 8'd64) & ddr_cmd_en & ddr_cmd_sel;
assign wr_fifo_alfull = (ddr_rddata_sel==1'b0)?gui_fifo_alfull:cmos_fifo_alfull;
assign gui_fifo_wr = ddr_rd_en & (~ddr_rddata_sel);
assign cmos_fifo_wr = ddr_rd_en & ddr_rddata_sel;
assign gui_valid = ({gui_r,gui_g,gui_b}!=0);

/********************** Generate pclk ********************************/
always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        pclk_cnt    <= 'h0;
    end
    else if(pclk_cnt==16'h0)
    begin
        pclk_cnt    <= #U_DLY PCLK_PERX2;
    end
    else if(buff_rdy)
    begin
        pclk_cnt    <= #U_DLY pclk_cnt - 1'b1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        lcd_pclk    <= 1'b0;
    end
    else if(pclk_cnt==16'h0)
    begin
        lcd_pclk    <= #U_DLY ~lcd_pclk;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        lcd_pclk_dly1   <= 1'b0;
    end
    else
    begin
        lcd_pclk_dly1   <= #U_DLY lcd_pclk;
    end
end

/****************************** Generate hsync ********************************/

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        h_cnt    <= 'h0;
    end
    else if(h_cnt==Th)
    begin
        h_cnt    <= #U_DLY 'h0;
    end
    else if(lcd_pclk_falling)
    begin
        h_cnt    <= #U_DLY h_cnt + 1'b1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        lcd_hsync       <= 1'b0;
        lcd_hsync_dly1  <= 1'b0;
    end
    else
    begin
        lcd_hsync       <= #U_DLY (h_cnt >= Thp);
        lcd_hsync_dly1  <= #U_DLY lcd_hsync;
    end
end

/****************************** Generate vsync ********************************/
always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        v_cnt    <= 'h0;
    end
    else if(v_cnt==Tv)
    begin
        v_cnt    <= #U_DLY 'h0;
    end
    else if(lcd_hsync_falling)
    begin
        v_cnt    <= #U_DLY v_cnt + 1'b1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        lcd_vsync       <= 1'b0;
        lcd_vsync_dly1  <= 1'b0;
    end
    else
    begin
        lcd_vsync       <= #U_DLY (v_cnt >= Tvp);
        lcd_vsync_dly1  <= #U_DLY lcd_vsync;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        h_enable    <= 1'b0;
    end
    else
    begin
        h_enable    <= #U_DLY (v_cnt >= Tvb1) & (v_cnt < Tvd1);
    end
end

/****************************** Generate lcd_de ********************************/
always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        lcd_de  <= 1'b0;
    end
    else if(h_enable)
    begin
        lcd_de  <= #U_DLY (h_cnt >= Thb1) & (h_cnt < Thd1);
    end
    else
    begin
        lcd_de  <= #U_DLY 1'b0;
    end
end

/****************************** Config reg ********************************/

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        lcd_vsync_rising_dly <= 1'b0;
    end
    else
    begin
        lcd_vsync_rising_dly <= #U_DLY lcd_vsync_rising;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        disp_mode_reg   <= 'h0;
        gui_sel_reg     <= 'h0;
    end
    else if(lcd_vsync_rising)
    begin
        disp_mode_reg   <= #U_DLY disp_mode;
        gui_sel_reg     <= #U_DLY gui_id[0];
    end
end

/****************************** DDR read ********************************/

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        ddr_buff_sel    <= 1'b0;
    end
    else if(buff0_done)
    begin
        ddr_buff_sel    <= #U_DLY 1'b0;
    end
    else if(buff1_done)
    begin
        ddr_buff_sel    <= #U_DLY 1'b1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        ddr_rddata_sel <= 1'b0;
    end
    else if(~ddr_rddata_sel & gui_line_done)
    begin
        ddr_rddata_sel <= #U_DLY 1'b1;
    end
    else if(ddr_rddata_sel & cmos_line_done)
    begin
        ddr_rddata_sel <= #U_DLY 1'b0;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        ddr_cmd_sel <= 1'b0;
    end
    else if(~ddr_cmd_sel & gui_cmd_done)
    begin
        ddr_cmd_sel <= #U_DLY 1'b1;
    end
    else if(ddr_cmd_sel & cmos_cmd_done)
    begin
        ddr_cmd_sel <= #U_DLY 1'b0;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        gui_line_addr   <= 'h0;
    end
    else if(lcd_vsync_rising_dly)
    begin
        case({gui_sel_reg,disp_mode_reg[2]})
            2'b00: gui_line_addr    <= #U_DLY GUI0_BASE;
            2'b01: gui_line_addr    <= #U_DLY GUI0_LAST;
            2'b10: gui_line_addr    <= #U_DLY GUI1_BASE;
            2'b11: gui_line_addr    <= #U_DLY GUI1_LAST;
        endcase
    end
    else if(gui_cmd_done)
    begin
        gui_line_addr <= #U_DLY (disp_mode_reg[2]==1'b1)?(gui_line_addr - GUI_LINE_LEN):(gui_line_addr + GUI_LINE_LEN);
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        line_rep <= 1'b0;
    end
    else if(cmos_cmd_done & (^disp_mode_reg[1:0]))
    begin
        line_rep <= #U_DLY ~line_rep;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        line_change <= 1'b0;
    end
    else
    begin
        case(disp_mode_reg[1:0])
            2'b00: line_change <= #U_DLY 1'b1;
            2'b01: line_change <= #U_DLY line_rep;
            2'b10: line_change <= #U_DLY line_rep;
            2'b11: line_change <= #U_DLY 1'b1;
        endcase 
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        cmos_line_addr  <= 'h0;
    end
    else if(lcd_vsync_rising_dly)
    begin
        case(disp_mode_reg[2:0])
            3'b001: cmos_line_addr  <= #U_DLY (ddr_buff_sel==1'b0)?BUFF0_XBASE:BUFF1_XBASE;    // Normal,G+X
            3'b010: cmos_line_addr  <= #U_DLY (ddr_buff_sel==1'b0)?BUFF0_YBASE:BUFF1_YBASE;    // Normal,G+Y
            3'b011: cmos_line_addr  <= #U_DLY (ddr_buff_sel==1'b0)?BUFF0_XBASE:BUFF1_XBASE;    // Normal,G+X+Y
            3'b101: cmos_line_addr  <= #U_DLY (ddr_buff_sel==1'b0)?BUFF0_XLAST:BUFF1_XLAST;    // Inverse,G+X
            3'b110: cmos_line_addr  <= #U_DLY (ddr_buff_sel==1'b0)?BUFF0_YLAST:BUFF1_YLAST;    // Inverse,G+Y
            3'b111: cmos_line_addr  <= #U_DLY (ddr_buff_sel==1'b0)?BUFF0_YLAST:BUFF1_YLAST;    // Inverse,G+X+Y
        endcase
    end
    else if(cmos_cmd_done & line_change)
    begin
        cmos_line_addr <= #U_DLY (disp_mode_reg[2]==1'b1)?(cmos_line_addr - CMOS_LINE_LEN):(cmos_line_addr + CMOS_LINE_LEN);
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        line_point    <= 'h0;
    end
    else if(cmos_cmd_done | gui_cmd_done)
    begin
        line_point    <= #U_DLY 'h0;
    end
    else if(ddr_cmd_en)
    begin
        line_point    <= #U_DLY line_point + {(ddr_cmd_bl + 1),2'b00};
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        frame_done <= 1'b1;
    end
    else
    begin
        frame_done <= #U_DLY gui_done & cmos_done;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        gui_pending_cnt <= 'h0;
    end
    else if(buff_rdy & lcd_vsync_rising)
    begin
        gui_pending_cnt <= #U_DLY GUI_LEN;
    end
    else if(ddr_cmd_en & (~ddr_cmd_sel))
    begin
        gui_pending_cnt <= #U_DLY gui_pending_cnt - ddr_cmd_bl - 1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        cmos_pending_cnt <= 'h0;
    end
    else if(buff_rdy & lcd_vsync_rising)
    begin
        cmos_pending_cnt <= #U_DLY CMOS_LEN;
    end
    else if(ddr_cmd_en & ddr_cmd_sel)
    begin
        cmos_pending_cnt <= #U_DLY cmos_pending_cnt - ddr_cmd_bl - 1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        ddr_rd_cnt <= 'h0;
    end
    else if(ddr_cmd_en)
    begin
        ddr_rd_cnt <= #U_DLY ddr_cmd_bl + 1'b1;
    end
    else if(ddr_rd_en)
    begin
        ddr_rd_cnt <= #U_DLY ddr_rd_cnt - 1'b1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        ddr_cmd_en  <= 1'b0;
    end
    else if(~frame_done & ddr_rd_done)
    begin
        ddr_cmd_en  <= #U_DLY ~ddr_cmd_full & ~ddr_cmd_en;
    end
    else
    begin
        ddr_cmd_en  <= #U_DLY 1'b0;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        gui_line_bl  <= 'h0;
    end
    else if(gui_line_bl==0)
    begin
        gui_line_bl  <= #U_DLY GUI_BL;  // bl 0 means 1
    end
    else if(ddr_cmd_en & (~ddr_cmd_sel))
    begin
        gui_line_bl  <= #U_DLY gui_line_bl - gui_rd_bl - 1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        cmos_line_bl  <= 'h0;
    end
    else if(cmos_line_bl==0)
    begin
        cmos_line_bl  <= #U_DLY CMOS_BL;  // bl 0 means 1
    end
    else if(ddr_cmd_en & ddr_cmd_sel)
    begin
        cmos_line_bl  <= #U_DLY cmos_line_bl - cmos_rd_bl - 1;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        ddr_cmd_bl  <= 'h0;
    end
    else
    begin
        ddr_cmd_bl  <= #U_DLY (ddr_cmd_sel==1'b0)?gui_rd_bl:cmos_rd_bl;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        ddr_rd_en   <= 1'b0;
    end
    else if(~wr_fifo_alfull)
    begin
        ddr_rd_en   <= #U_DLY ~ddr_rd_en & (~ddr_rd_empty);
    end
    else
    begin
        ddr_rd_en   <= #U_DLY 1'b0;
    end
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        gui_line_cnt <= 'h0;
    end
    else if(gui_line_done)
    begin
        gui_line_cnt   <= #U_DLY 'h0;
    end
    else if(gui_fifo_wr)
    begin
        gui_line_cnt   <= #U_DLY gui_line_cnt + 1'b1;
    end 
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        cmos_line_cnt <= 'h0;
    end
    else if(cmos_line_done)
    begin
        cmos_line_cnt   <= #U_DLY 'h0;
    end
    else if(cmos_fifo_wr)
    begin
        cmos_line_cnt   <= #U_DLY cmos_line_cnt + 1'b1;
    end 
end

always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        buff_rdreq   <= 1'b0;
    end
    else if(lcd_de & lcd_pclk_falling)
    begin
        buff_rdreq   <= #U_DLY 1'b1;
    end
    else
    begin
        buff_rdreq   <= #U_DLY 1'b0;
    end
end

// 2'b00 = gui; 2'b01 = gui+cmos_x;2'b10 = gui+cmos_y;2'b11 = gui+coms_x+cmos_y;
always@(posedge clk,posedge rst)
begin
    if(rst==1'b1)
    begin
        lcd_r   <= 'h0;
        lcd_g   <= 'h0;
        lcd_b   <= 'h0;
    end
    else if(disp_mode_reg[1:0]==2'h0)
    begin
        lcd_r   <= #U_DLY gui_r;
        lcd_g   <= #U_DLY gui_g;
        lcd_b   <= #U_DLY gui_b;
    end
    else
    begin
        lcd_r   <= #U_DLY (gui_valid==1'b1)?gui_r:cmos_data;
        lcd_g   <= #U_DLY (gui_valid==1'b1)?gui_g:cmos_data;
        lcd_b   <= #U_DLY (gui_valid==1'b1)?gui_b:cmos_data;
    end
end

// instance
lcd_rgb_buff u_rgb
(
    .clk                (clk),
    .rst                (rst),

    // line buffer fifo 
    .in_fifo_rddata     (gui_fifo_rddata),
    .in_fifo_rdreq      (gui_fifo_rd),
    .in_fifo_empty      (gui_fifo_empty),
    .in_fifo_alempty    (gui_fifo_alempty),

    //lcd output fifo
    .out_fifo_data_r    (gui_r),
    .out_fifo_data_g    (gui_g),
    .out_fifo_data_b    (gui_b),
    .out_fifo_empty     (),
    .out_fifo_alempty   (),
    .out_fifo_rdreq     (buff_rdreq)
);

lcd_gray_buff u_gray
(
    .clk                (clk),
    .rst                (rst),

    // line buffer fifo 
    .in_fifo_rddata     (cmos_fifo_rddata),
    .in_fifo_rdreq      (cmos_fifo_rd),
    .in_fifo_empty      (cmos_fifo_empty),
    .in_fifo_alempty    (cmos_fifo_alempty),

    //lcd output fifo
    .out_fifo_data      (cmos_data),
    .out_fifo_empty     (),
    .out_fifo_alempty   (),
    .out_fifo_rdreq     (buff_rdreq)
);

SCFIFO_256X32D gui_buff(
  .clk          (clk),
  .rst          (rst),
  .din          (ddr_rd_data),
  .wr_en        (gui_fifo_wr),
  .rd_en        (gui_fifo_rd),
  .dout         (gui_fifo_rddata),
  .full         (),
  .almost_full  (gui_fifo_alfull),
  .empty        (gui_fifo_empty),
  .almost_empty (gui_fifo_alempty)
);

SCFIFO_256X32D cmos_buff(
  .clk          (clk),
  .rst          (rst),
  .din          (ddr_rd_data),
  .wr_en        (cmos_fifo_wr),
  .rd_en        (cmos_fifo_rd),
  .dout         (cmos_fifo_rddata),
  .full         (),
  .almost_full  (cmos_fifo_alfull),
  .empty        (cmos_fifo_empty),
  .almost_empty (cmos_fifo_alempty)
);

endmodule
